//-------------------------------------------------------------------------
//
//  Copyright (c) 1999 Cornell University
//  Computer Systems Laboratory
//  Cornell University, Ithaca, NY 14853
//  All Rights Reserved
//
//  Permission to use, copy, modify, and distribute this software
//  and its documentation for any purpose and without fee is hereby
//  granted, provided that the above copyright notice appear in all
//  copies. Cornell University makes no representations
//  about the suitability of this software for any purpose. It is
//  provided "as is" without express or implied warranty. Export of this
//  software outside of the United States of America may require an
//  export license.
//
//  $Id: mips.v,v 1.1.1.1 2003/01/16 19:49:43 heinrich Exp $
//
//-------------------------------------------------------------------------

`include "mips.h"

module TOP;

reg	[31:0]	Din;
reg	[31:0]	Iin;
reg		MRST, CLK;

wire	[31:0]	Daddr;			// Address for data access
wire		Dread;			// Data read
wire		Dwrite;			// Data write enable
wire	[1:0]	Dsize;			// Data write enable
wire	[31:0]	Dout;			// Write path to data cache
wire	[31:0]	Iaddr;			// Address for instruction access

// Create a 50% duty cycle clock
initial begin
   CLK = 1;
   forever begin
      `PHASE
      CLK = 0;
      `PHASE
      CLK = 1;
   end 
end 

initial begin
   MRST = 1;
   #86 MRST = 0;
end 

cpu	CPU			// Instantiate CPU
(
   .CLK		(CLK),
   .MRST	(MRST),
   .Din		(Din),
   .Iin		(Iin),
   .Iaddr  	(Iaddr),
   .Daddr  	(Daddr),
   .Dwrite 	(Dwrite),
   .Dread  	(Dread),
   .Dsize  	(Dsize),
   .Dout   	(Dout)
);

initial
begin
   $seed_mm;
end


always @(Iaddr) begin		// Mimic external memory
//   $display("pc=%h: ", Iaddr);
   Iin = $load_mm (Iaddr);
//   $disasm (Iin);
end

always @(Dread or Daddr) begin
   if (Dread) begin
      Din = $load_mm (Daddr);
   end
end

reg	    [31:0]	tempStoreData;
reg 	[4:0]	sa;
reg 	[31:0]	mask;
reg 	[31:0]	value;

// Handle writes to the memory syste.  Partial word writes are actually
// handled as read-modify-write transactions

//always @(Dwrite or Daddr or Dsize or Dout)
always @(negedge CLK)
begin
   if (Dwrite) begin
      if (Dsize == `SIZE_WORD) begin
	 $store_mm (Daddr, Dout);
      end
      else if (Dsize == `SIZE_HALF) begin
         tempStoreData = $load_mm (Daddr);
         sa = ((~Daddr >> 1)  & 32'h1) << 4;
         mask = 32'hffff << sa;
         value = (tempStoreData & ~mask) | ((Dout & 32'hffff) << sa);
         $store_mm(Daddr,value); 
      end
      else if (Dsize == `SIZE_BYTE) begin
	 tempStoreData = $load_mm (Daddr);
	 sa = (~Daddr & 32'h3) << 3;
	 mask = 32'hff << sa;
	 value = (tempStoreData & ~mask) | ((Dout & 32'hff) << sa);
	 $store_mm (Daddr, value);
      end
      else begin
	 $display("Error: Unsupported store size %h\n", Dsize);
	 $finish;
      end
   end
end

//---------------------------------------------------------------------

endmodule

